"""
货物管理服务
"""
from typing import List, Optional, Tuple
from tortoise.exceptions import DoesNotExist, IntegrityError
from tortoise.queryset import QuerySet
from fastapi import HTTPException, status
from loguru import logger

from app.models.cargo import Cargo, CargoCategory, CargoImage, CargoAttribute
from app.schemas.cargo import (
    CargoCreate, CargoUpdate, CargoResponse,
    CargoCategoryCreate, CargoCategoryUpdate, CargoCategoryResponse,
    CargoImageCreate, CargoImageResponse,
    CargoAttributeCreate, CargoAttributeResponse
)
from app.utils.security import generate_code


class CargoService:
    """货物服务类"""
    
    @staticmethod
    async def create_cargo(cargo_data: CargoCreate) -> CargoResponse:
        """创建货物"""
        try:
            # 检查分类是否存在
            category = await CargoCategory.get_or_none(id=cargo_data.category_id)
            if not category:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="货物分类不存在"
                )
            
            # 检查编码是否重复
            existing_cargo = await Cargo.get_or_none(code=cargo_data.code)
            if existing_cargo:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="货物编码已存在"
                )
            
            # 如果没有提供编码，自动生成
            if not cargo_data.code:
                cargo_data.code = generate_code("CARGO")
            
            # 创建货物
            cargo = await Cargo.create(**cargo_data.dict())
            
            # 获取完整的货物信息
            cargo_with_relations = await Cargo.get(id=cargo.id).prefetch_related("category")
            
            logger.info(f"创建货物成功: {cargo.name} ({cargo.code})")
            return CargoResponse.from_orm(cargo_with_relations)
            
        except IntegrityError as e:
            logger.error(f"创建货物失败，数据完整性错误: {e}")
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="数据完整性错误，请检查输入数据"
            )
        except Exception as e:
            logger.error(f"创建货物失败: {e}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="创建货物失败"
            )
    
    @staticmethod
    async def get_cargo(cargo_id: int) -> CargoResponse:
        """获取货物详情"""
        try:
            cargo = await Cargo.get(id=cargo_id).prefetch_related("category")
            return CargoResponse.from_orm(cargo)
        except DoesNotExist:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="货物不存在"
            )
    
    @staticmethod
    async def update_cargo(cargo_id: int, cargo_data: CargoUpdate) -> CargoResponse:
        """更新货物"""
        try:
            cargo = await Cargo.get(id=cargo_id)
            
            # 如果更新分类，检查分类是否存在
            if cargo_data.category_id:
                category = await CargoCategory.get_or_none(id=cargo_data.category_id)
                if not category:
                    raise HTTPException(
                        status_code=status.HTTP_400_BAD_REQUEST,
                        detail="货物分类不存在"
                    )
            
            # 更新货物信息
            update_data = cargo_data.dict(exclude_unset=True)
            await cargo.update_from_dict(update_data)
            await cargo.save()
            
            # 获取更新后的货物信息
            updated_cargo = await Cargo.get(id=cargo_id).prefetch_related("category")
            
            logger.info(f"更新货物成功: {cargo.name} ({cargo.code})")
            return CargoResponse.from_orm(updated_cargo)
            
        except DoesNotExist:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="货物不存在"
            )
        except Exception as e:
            logger.error(f"更新货物失败: {e}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="更新货物失败"
            )
    
    @staticmethod
    async def delete_cargo(cargo_id: int) -> bool:
        """删除货物"""
        try:
            cargo = await Cargo.get(id=cargo_id)
            await cargo.delete()
            
            logger.info(f"删除货物成功: {cargo.name} ({cargo.code})")
            return True
            
        except DoesNotExist:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="货物不存在"
            )
        except Exception as e:
            logger.error(f"删除货物失败: {e}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="删除货物失败"
            )
    
    @staticmethod
    async def list_cargos(
        page: int = 1,
        size: int = 20,
        category_id: Optional[int] = None,
        status: Optional[str] = None,
        search: Optional[str] = None
    ) -> Tuple[List[CargoResponse], int]:
        """获取货物列表"""
        try:
            # 构建查询
            query = Cargo.all().prefetch_related("category")
            
            # 按分类筛选
            if category_id:
                query = query.filter(category_id=category_id)
            
            # 按状态筛选
            if status:
                query = query.filter(status=status)
            
            # 搜索
            if search:
                query = query.filter(
                    name__icontains=search
                ).union(
                    Cargo.filter(code__icontains=search)
                ).union(
                    Cargo.filter(brand__icontains=search)
                )
            
            # 获取总数
            total = await query.count()
            
            # 分页
            offset = (page - 1) * size
            cargos = await query.offset(offset).limit(size)
            
            # 转换为响应模式
            cargo_responses = [CargoResponse.from_orm(cargo) for cargo in cargos]
            
            return cargo_responses, total
            
        except Exception as e:
            logger.error(f"获取货物列表失败: {e}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="获取货物列表失败"
            )


class CargoCategoryService:
    """货物分类服务类"""
    
    @staticmethod
    async def create_category(category_data: CargoCategoryCreate) -> CargoCategoryResponse:
        """创建货物分类"""
        try:
            # 检查编码是否重复
            existing_category = await CargoCategory.get_or_none(code=category_data.code)
            if existing_category:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="分类编码已存在"
                )
            
            # 如果有父分类，检查父分类是否存在
            if category_data.parent_id:
                parent = await CargoCategory.get_or_none(id=category_data.parent_id)
                if not parent:
                    raise HTTPException(
                        status_code=status.HTTP_400_BAD_REQUEST,
                        detail="父分类不存在"
                    )
                category_data.level = parent.level + 1
            
            # 创建分类
            category = await CargoCategory.create(**category_data.dict())
            
            logger.info(f"创建货物分类成功: {category.name} ({category.code})")
            return CargoCategoryResponse.from_orm(category)
            
        except IntegrityError as e:
            logger.error(f"创建货物分类失败，数据完整性错误: {e}")
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="数据完整性错误，请检查输入数据"
            )
        except Exception as e:
            logger.error(f"创建货物分类失败: {e}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="创建货物分类失败"
            )
    
    @staticmethod
    async def get_category_tree() -> List[CargoCategoryResponse]:
        """获取分类树"""
        try:
            # 获取所有分类
            categories = await CargoCategory.all().order_by("level", "sort_order")
            
            # 构建分类树
            category_dict = {}
            root_categories = []
            
            for category in categories:
                category_response = CargoCategoryResponse.from_orm(category)
                category_dict[category.id] = category_response
                
                if category.parent_id is None:
                    root_categories.append(category_response)
                else:
                    parent = category_dict.get(category.parent_id)
                    if parent:
                        if parent.children is None:
                            parent.children = []
                        parent.children.append(category_response)
            
            return root_categories
            
        except Exception as e:
            logger.error(f"获取分类树失败: {e}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="获取分类树失败"
            )
